/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.IO;
using OpenServers.Net.Common.Utils;

namespace OpenServers.Net.Common.FileSystem.Http {
    /// <summary>
    /// A directory which proxies request to an HTTP server for it's data.
    /// </summary>
    public class HttpDirectory : IDirectory {
        private readonly string _name;
        private readonly IDirectory _parent;
        private readonly Url _url;
        private DirectoryInfo _cacheDir;
        private IDictionary<string, IFileSystemObject> _children = new Dictionary<string, IFileSystemObject>();

        /// <summary>
        /// Constructor which will derive it's name from the url.
        /// </summary>
        public HttpDirectory(IDirectory parent, Url url)
            : this(parent, null, url) {
        }

        /// <summary>
        /// Constructor that initializes the name field, overriding the default to pull from the url. Also overrides the default cache location.
        /// </summary>
        public HttpDirectory(IDirectory parent, string name, Url url) {
            _parent = parent;
            _name = name;
            _url = url;
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public IList<IFileSystemObject> GetItems() {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public IList<IDirectory> GetDirectories() {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public void Create() {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public IFile CreateFile(string name) {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public IDirectory CreateDirectory(string name) {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets an object from the directory.
        /// </summary>
        /// <param name="path">The path is seperated by '/'</param>
        public virtual IFileSystemObject GetObject(string path) {
            if (path.StartsWith("/")) {
                path = path.Substring(1);
            }
            int pathSeperator = path.IndexOf('/');
            if (pathSeperator > 0) {
                string nextPathPart = path.Substring(0, pathSeperator);
                string restOfPath = path.Substring(pathSeperator + 1);

                if (_children.ContainsKey(nextPathPart)) {
                    IFileSystemObject child = _children[nextPathPart];
                    if (child is IDirectory) {
                        return ((IDirectory)child).GetObject(restOfPath);
                    } else {
                        throw new ApplicationException(nextPathPart + " is a file.");
                    }
                } else {
                    Url newUrl = new Url(Url.ToString());
                    newUrl.Path = newUrl.Path + nextPathPart + "/";
                    HttpDirectory newDir = CreateSubdirectory(nextPathPart, newUrl);
                    _children.Add(nextPathPart, newDir);
                    if (string.IsNullOrEmpty(restOfPath)) {
                        return newDir;
                    }
                    return newDir.GetObject(restOfPath);
                }
            } else {
                if (_children.ContainsKey(path)) {
                    return _children[path];
                } else {
                    Url newUrl = new Url(Url.ToString());
                    newUrl.Path = newUrl.Path + path;
                    HttpFile file = CreateSubfile(newUrl);
                    _children.Add(path, file);
                    return file;
                }
            }
        }

        /// <summary>
        /// Creates a sub file.
        /// </summary>
        protected virtual HttpFile CreateSubfile(Url url) {
            return new HttpFile(this, url);
        }

        /// <summary>
        /// Creates a sub directory.
        /// </summary>
        protected virtual HttpDirectory CreateSubdirectory(string name, Url url) {
            return new HttpDirectory(this, name, url);
        }

        /// <summary>
        /// The name of the object.
        /// </summary>
        public string Name {
            get {
                if (_name == null) {
                    string path = _url.Path;
                    path = path.TrimEnd('/');
                    int lastDir = path.LastIndexOf('/');
                    if (lastDir >= 0) {
                        return path.Substring(lastDir + 1);
                    }
                }
                return _name;
            }
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public DateTime LastModified {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public void Delete() {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public bool Exists {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// The parent object.
        /// </summary>
        public IDirectory Parent {
            get { return _parent; }
        }

        /// <summary>
        /// flag marking this object as read only.
        /// </summary>
        public bool ReadOnly {
            get { return true; }
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        public void MoveTo(IFileSystemObject fso) {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets the full path of this object.
        /// </summary>
        public string FullPath {
            get { return FileSystemUtils.GetFullPath(this); }
        }

        ///<summary>
        /// The url of this directory.
        ///</summary>
        public Url Url {
            get { return _url; }
        }

        ///<summary>
        /// The directory which contains the cache for this directory.
        ///</summary>
        public DirectoryInfo CacheDir {
            get {
                if (_cacheDir == null) {
                    string cachePath;
                    if (Parent is HttpDirectory) {
                        cachePath = Path.Combine(((HttpDirectory)Parent).CacheDir.FullName, Name);
                    } else {
                        cachePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
                    }
                    _cacheDir = new DirectoryInfo(cachePath);
                    CacheDir.Create();
                }

                return _cacheDir;
            }
        }
    }
}
